home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d1 / freemacs.arc / MINTSCAN.ASM < prev    next >
Assembly Source File  |  1988-03-17  |  14KB  |  505 lines

  1. ;History:90,26
  2.     page    ,132
  3.  
  4.     .xlist
  5.     include mintdefs.asm
  6.     .list
  7.  
  8. HT    equ    9
  9. LF    equ    10
  10. CR    equ    13
  11.  
  12. data    segment byte public
  13.  
  14. comment /******************************************************************
  15.  
  16. Introduction:
  17.  
  18.     The MINT data structures are laid out in memory as given below.
  19. First are the variables, followed by the neutral string.  Next is the
  20. block of free memory.  Last is the active string followed by forms.
  21.  
  22.     variables, neutral string ... free memory ... neutral string, forms
  23.  
  24. The neutral string:
  25.  
  26.     The neutral string consists of a list of arguments.  Each argument
  27. begins with header which might be laid out as so in Pascal:
  28.     arg_header = record
  29.      marker : (active_marker, neutral_marker, comma_marker);
  30.      previous : ^arg_header;
  31.     end;
  32.  
  33. The pointer, previous, points to the previous arg_header. The last one in the
  34. list has a nil pointer.  This will always be the #(ps) which is the outermost
  35. function to be executed.
  36.  
  37. The neutral string during function execution:
  38.  
  39.     Since we are interested in counting arguments from left to right,
  40. not right to left, we need to reverse the pointers so that they point
  41. from the first argument, to the second argument, to the third argument,
  42. etc.  At this point, [fbgn] points to the first argument (the name of the
  43. funciton), and [fend] points past the last argument.  To make argument
  44. fetching more efficient, the last argument is followed by a null argument
  45. which points to itself.  This causes missing arguments to be fetched as
  46. nulls, in according to the definition of the language.
  47.     Functions which return a value will build that value at either
  48. [fbgn]-1 or [fend]-2, depending on whether or not they need to refer to
  49. arguments supplied to the function.  In general, single argument functions
  50. will use [fbgn]-1, and multiple argument functions will use [fend]-2.
  51.  
  52. Neutral function results will eventually be moved to [fbgn]-1.
  53.  
  54. The active string:
  55.  
  56.     The active string consists of a string of ASCII characters which
  57. have not yet been scanned.  Typically, only ASCII characters appear here,
  58. although any eight bit value may occur.
  59.  
  60. The active string during function execution:
  61.  
  62.     [actptr] points to the end of the active string.  Active function
  63. results are built as described above and then moved to the left of [actptr].
  64. Actptr is then adjusted to point to the result just moved in.  Primitives
  65. check for memory overflow by comparing [fend] to [actptr].  If they come
  66. closer than some magic constant, then the 'No Memory' error is given
  67. and the idling string is reloaded.
  68.  
  69.  
  70. The forms:
  71.  
  72.     Forms are laid out as a linear list of forms.  [formb] points to the
  73. beginning, and [forme] points to the end.  The most recently defined forms are
  74. placed at the beginning of the list.  The forms consists of three elements: a
  75. header, the name, and the data.  The header contains the link to the next
  76. form, the length of the name, the length of the data, and the form pointer
  77. (which is always <= the length of the data).  The form structure is defined in
  78. the file 'mintdefs.asm'.
  79.     When a form is to be looked up in form storage, the form is first
  80. hashed.  Then the form is looked up in the list of hash links.  A linear search
  81. is performed for all the forms that hash to that value.
  82.  
  83.  
  84.  
  85. **************************************************************************/
  86.  
  87.  
  88.     public    trace
  89.     public    next_ids
  90.     extrn    standard_ids: byte
  91.     public    formb, forme, fbgn, fend, actptr
  92.     extrn    lomem: byte
  93.  
  94. trace    db    0        ;trace is initially off.
  95. next_ids    dw    standard_ids
  96. formb    dw    ?
  97. forme    dw    ?
  98. fbgn    dw    ?
  99. fend    dw    ?
  100. actptr    dw    ?
  101. fcn_save    db    ?
  102. prev_fcn    dw    ?
  103.  
  104. ;some constant definitions
  105.  
  106. ;the _mark constants mark where a particular type of string occurs in
  107. ; the linked list.
  108.  
  109. comma_marker    equ    0    ;comma_marker must not have function_marker_mask set!
  110. active_marker    equ    1    ;active_marker must have function_marker_mask set!
  111. neutral_marker    equ    3    ;neutral_marker must have function_marker_mask set!
  112. function_marker_mask    equ    1
  113.  
  114. entry    macro    char, adr
  115.     org    (offset scan_xlat_table)+char
  116.     db    (offset adr)-(offset scan_loop)
  117.     endm
  118.  
  119. scan_xlat_table    db    256 dup ((offset scan_copy)-(offset scan_loop))
  120. ;first, fill up the table with 'copy'
  121. ;next, put the proper addresses in the right spots,
  122.     entry    HT,scan_ignore
  123.     entry    CR,scan_ignore
  124.     entry    LF,scan_ignore
  125.     entry    '#',scan_sharp
  126.     entry    '(',scan_lpar
  127.     entry    ')',scan_rpar
  128.     entry    ',',scan_comma
  129. ;finally, go to the end of the table.
  130.     org    (offset scan_xlat_table)+(size scan_xlat_table)
  131.  
  132.     purge    entry
  133.  
  134.     extrn    function_name_table: word
  135.     extrn    function_name_length: word
  136.     extrn    function_address: word
  137.  
  138. nomem_prompt        db    'No memory!',0
  139. fatal_prompt        db    'No disk in drive or door open!',0
  140. protected_prompt    db    'Disk is write protected!',0
  141.  
  142.     extrn    stackp: byte
  143.  
  144. data    ends
  145.  
  146.  
  147. code    segment byte public
  148.  
  149.     assume    cs:code, ds:data, es:data
  150.  
  151.     public    abort_fatal
  152. abort_fatal:
  153.     add    sp,22            ;magic number from Z-DOS II, page I.3
  154.     pop    es            ;restore our es and ds.
  155.     push    es
  156.     pop    ds
  157.     mov    sp,offset stackp
  158.     sti                ;enable interrupts again.
  159.     mov    si,offset protected_prompt
  160.     cmp    di,0            ;write protect?
  161.     je    nomem_1
  162.     mov    si,offset fatal_prompt
  163.     jmp    short nomem_1
  164.     public    nomem
  165. nomem:
  166.     mov    sp,offset stackp
  167.     mov    si,offset nomem_prompt
  168. nomem_1:
  169.     lodsb
  170.     or    al,al
  171.     je    nomem_2
  172.     mov    dl,al
  173.     mov    ah,2
  174.     int    21h
  175.     jmp    nomem_1
  176. nomem_2:
  177.     jmp    init_ids
  178.  
  179.     extrn    init_ids: near
  180.  
  181.     public    init_ids_continue
  182. init_ids_continue:
  183.     mov    di,next_ids        ;get the desired idling string.
  184.     mov    si,di            ;save a copy
  185.     mov    next_ids,offset standard_ids    ;reset to ids.
  186.     mov    al,0
  187.     mov    cx,-1
  188.     repne    scasb        ;find the terminating null.
  189.     not    cx
  190.     mov    di,formb
  191.     sub    di,cx
  192.     push    di
  193.     rep    movsb
  194.     pop    si        ;pushed as di
  195.     mov    di,offset lomem
  196.     mov    dx,0
  197.     cld
  198.     mov    bp,formb
  199.     mov    bx,offset scan_xlat_table    ;->translate table
  200.     jmp    short scan_loop
  201. init_ids_jump_2:
  202.     jmp    init_ids
  203.  
  204.  
  205. comment /*******************************************************************
  206.     The following is the MINT scan loop.  This loop must be as fast as
  207. possible because it takes the most time to execute.   As a consequence, the
  208. code is quite unstructured.  However, the code follows the algorithm given in
  209. the MINT language definition document.
  210.     During scan, si -> (points to) the active string, di -> the
  211. neutral string, dx -> previous argument, and bp -> end of active string.
  212.     As we scan a character, we must branch to certain routines on certain
  213. characters.  To make best use of the 8086 instruction set, we have set up a
  214. translate table.  Therefore, the translate table, scan_xlat_table, contains an
  215. offset from the beginning of the scan loop.
  216.  
  217.     When the scan loop has finally found a function to be executed,
  218. a jump is performed to that primitive (unknown primitives cause jump to dflt).
  219. When the primitive is finished, it jumps (with the exception of hl) to one of
  220. the 'return_???' functions.  Each of the return_??? routines puts the returned
  221. value in the proper place in the proper string (active or neutral), and jumps
  222. back to scan.
  223.     The scan loop is repeatedly executed until there are no more functions
  224. to be executed, or the available memory has been exhausted.
  225. *****************************************************************************/
  226.  
  227. scan_copy:            ;come here to copy a char from active to neutral
  228.     dec    si
  229.     movsb
  230. scan_ignore:            ;come here to throw a char away from active.
  231. scan_loop:
  232.     cmp    si,bp        ;if we scan off the right end, init_ids
  233.     je    init_ids_jump_2
  234.     lodsb
  235.     xlat            ;al was char, is now offset
  236.     cbw            ;ax is now offset.
  237.     add    ax,offset scan_loop
  238.     jmp    ax
  239.  
  240. scan_comma:
  241.     mov    al,comma_marker
  242. scan_mark:
  243.     stosb            ;store marker
  244.     mov    ax,dx        ;get previous pointer
  245.     mov    dx,di        ;save current (will soon be previous)
  246.     stosw
  247.     jmp    scan_loop
  248.  
  249. scan_sharp:
  250.     cmp    word ptr [si],'(#'    ;'##(' ?
  251.     je    scan_two_sharps        ;yes.
  252.     cmp    byte ptr [si],'('    ;'#(' ?
  253.     jne    scan_copy        ;no.
  254.     inc    si
  255.     mov    al,active_marker
  256.     jmp    scan_mark
  257. scan_two_sharps:
  258.     add    si,2
  259.     mov    al,neutral_marker
  260.     jmp    scan_mark
  261.  
  262. scan_lpar:
  263.     mov    cx,1
  264.     call    scan_lpar_sub
  265.     jmp    scan_loop
  266.  
  267. ;scan until we find a matching rpar.
  268.     public    scan_lpar_sub        ;public so that we can profile it.
  269. scan_lpar_sub:
  270.  
  271. scan_lpar_1:
  272.     cmp    si,bp
  273.     je    init_ids_jump_2
  274.     lodsb            ;can't use movsb, because it doesn't load al
  275.     stosb
  276.     cmp    al,'('
  277.     je    scan_lpar_2
  278.     cmp    al,')'
  279.     jne    scan_lpar_1
  280.     loop    scan_lpar_1
  281.     dec    di        ;remove final rpar
  282.     ret
  283. scan_lpar_2:
  284.     inc    cx
  285.     jmp    scan_lpar_1
  286.  
  287.  
  288. init_ids_jump_1:    jmp    init_ids
  289.  
  290. scan_rpar:
  291. ;si -> neutral string
  292. ;di -> active string
  293. ;dx -> previous argument or function pointer.
  294.     call    scan_rpar_sub
  295.     call    function_address[di - 2]
  296.     mov    bp,formb
  297.     mov    bx,offset scan_xlat_table    ;->translate table
  298.     jmp    scan_loop
  299.  
  300.  
  301.     public    scan_rpar_sub
  302. scan_rpar_sub:
  303. ;store last argument mark
  304.     mov    al,comma_marker
  305.     stosb
  306.     mov    ax,di        ;make final arg -> itself
  307.     stosw
  308. comment !can't use slash***************************************************
  309.     We have a problem here.  Currently, the pointers point backwards
  310. to the previous function/arg.  We want this function's pointers to point
  311. forwards, so we can start at the active/neutral marker and count arguments
  312. forwards.
  313.  
  314.      ¥¥ is a pointer, ò is what is points to.
  315.  
  316.  
  317.     a¥¥SS,¥¥ONE,¥¥TWO,¥¥
  318.       ò   éò    éò    éò
  319.       é   éé    éé    éé
  320.       ¢¥¥¥Ü¢¥¥¥¥Üé    ¢Ü
  321.              dx
  322. **********************************************************************!
  323.     mov    fend,di
  324.     sub    di,2        ;make di ->final pointer
  325.     mov    actptr,si
  326. scan_rpar_1:
  327.     cmp    dx,0        ;if end of list, we must be running off
  328.     je    init_ids_jump_1    ; the left end (too many rpars)
  329.     mov    bx,dx        ;get previous pointer.
  330.     mov    dx,[bx]        ;get the current pointer [previous pointer].
  331.     mov    [bx],di        ;store the next pointer.
  332.     mov    di,bx        ;save current pointer.
  333. ; bx, di -> current arg/fcn
  334. ; dx -> previous (to the left) arg/fcn
  335.     test    byte ptr -1[bx],function_marker_mask
  336.     jz    scan_rpar_1
  337.     mov    al,-1[bx]
  338.     mov    fcn_save,al        ;remember the type of function.
  339.     mov    prev_fcn,dx
  340.     mov    fbgn,bx
  341.     call    check_breakchar
  342.     call    trace_invoke        ;destroys al
  343. ;remember that fbgn is really one more than the space taken by the function.
  344.     mov    ax,[bx]            ;get pointer to first arg.
  345.     sub    ax,bx            ;compute length of name
  346.     cmp    ax,2 + mark_overhead    ;two character function name?
  347.     jne    default_to_cl        ;no - must be default.
  348.     mov    ax,2[bx]        ;get function name.
  349.     mov    di,offset function_name_table
  350.     mov    cx,offset function_name_length
  351.     repne    scasw
  352.     jne    default_to_cl        ;if not found, default
  353.     sub    di,offset function_name_table
  354.     ret
  355. default_to_cl:
  356.     mov    di,0
  357.     ret
  358.  
  359. ;return data routines here
  360.  
  361.     public    return_null
  362. return_null:
  363.     mov    cx,0
  364.     call    trace_result    ;destroys al
  365. return_nothing:
  366.     mov    si,actptr
  367.     mov    di,fbgn
  368.     dec    di
  369.     mov    dx,prev_fcn
  370.     ret
  371.  
  372.  
  373.     public    return_string
  374. return_string:
  375. ;al=string number to return, bx=>list of strings.
  376.     add    al,al
  377.     mov    ah,0
  378.     add    bx,ax
  379.     mov    si,[bx]
  380.     mov    cx,[bx+2]
  381.     sub    cx,si
  382.     jmp    return_sicx
  383.  
  384.  
  385.     public    return_tos
  386. return_tos:
  387. ;tos -> string, di -> byte after end of string
  388.     pop    si
  389.     mov    cx,di
  390.     sub    cx,si
  391.     jmp    short return_sicx
  392.  
  393.  
  394.     public    return_arg_active
  395. return_arg_active:
  396.     mov    fcn_save,active_marker
  397. ;fall through to return_arg
  398.  
  399.  
  400.     public    return_arg
  401. return_arg:
  402. ;enter with cx = number of arg to return.
  403.     call    getarg
  404. ;fall through to return_sicx
  405.  
  406.  
  407.     public    return_sicx
  408. return_sicx:
  409. ;si -> string, cx = count.
  410.     cmp    fcn_save,active_marker    ;active or neutral
  411.     jne    return_neutral
  412. ;    jmp    return_active        ;fall through!
  413.  
  414.  
  415.     public    return_active
  416. return_active:
  417. ;we need to move [si] count cx
  418. ; to [actptr-cx] through [actptr-1] reverse
  419. ;Then we return si = [actptr-cx], di=fbgn-1
  420.     call    trace_result    ;destroys al
  421.     jcxz    return_nothing    ;quick check for 0 chars.
  422.     mov    di,actptr
  423.     dec    di
  424.     add    si,cx        ;point si to end of string + 1.
  425.     dec    si        ;remember, it's postdecrement.
  426.     std            ;reverse move
  427.     rep    movsb
  428.     cld            ;everybody assumes it's cleared.
  429.     inc    di        ;make di -> last byte moved.
  430.     mov    si,di        ;si -> what we just moved.
  431.     mov    di,fbgn        ;remove previous function.
  432.     dec    di
  433.     mov    dx,prev_fcn
  434.     ret
  435.  
  436.     public    return_neutral
  437. return_neutral:
  438. ;we need to move [si] count cx
  439. ; to [fbgn-1] through [fbgn-1] - (cx - 1)
  440. ;Then we return si=actptr, di=[fbgn-1] - cx
  441.     call    trace_result    ;destroys al
  442.     jcxz    return_nothing    ;quick check for 0 chars.
  443.     mov    di,fbgn
  444.     dec    di
  445.     cmp    di,si        ;is it there already?
  446.     je    return_neutral_1    ;yes, save some time.
  447.     rep    movsb        ;put it there.
  448. return_neutral_1:
  449. ;tricky time!  If we performed the movsb, cx is zero, so we're doing
  450. ;nothing.  If we took the jump to return_neutral_1, cx is the proper
  451. ;count, so di will point to the right place.
  452.     add    di,cx
  453.     mov    si,actptr
  454.     mov    dx,prev_fcn
  455.     ret
  456.  
  457.  
  458.     extrn    trace_result: near
  459.     extrn    trace_invoke: near
  460.  
  461. ;utility subroutines
  462.  
  463.  
  464.     extrn    check_breakchar: near
  465.  
  466.  
  467.     public    getarg1, getarg
  468. getarg1:    mov    cx,1
  469.  
  470. ;fall through to getarg
  471.  
  472. getarg:
  473.  
  474. ;enter with cx = number of argument to get.
  475. ;exit with si -> argument, cx=length of argument.
  476.  
  477. comment /****************************************************************
  478.  
  479. The pointer after the last supplied argument points to itself, which allows
  480. us to loop at getarg_loop until we think that we have found the argument.  Of
  481. course, if that argument has not been supplied, all that we've done is to chase
  482. the last pointer a few times.  As an aside, had you ever noticed that when the
  483. amount of comments exceeds the amount of code, the code is likely to be
  484. confusing?  Well, this code is probably confusing.
  485.  
  486. *************************************************************************/
  487.     mov    si,fbgn
  488.     jcxz    getarg_2    ;skip loop if count is zero.
  489. getarg_loop:
  490.     mov    si,[si]        ;get our argument
  491.     loop    getarg_loop
  492. getarg_2:
  493.     mov    cx,[si]        ;get cx=next argument
  494.     sub    cx,si        ;get cx=length of our argument
  495.     jcxz    getarg_1    ;in case we ran into fend, it doesn't matter what si -> to.
  496.     sub    cx,mark_overhead
  497.     add    si,mark_overhead-1    ;make si-> text of argument.
  498. getarg_1:
  499.     ret
  500.  
  501. code    ends
  502.  
  503.     end
  504.  
  505.